package classifier;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import model.BlogPost;
import model.Sentence;

public class HierarchicalClassifier {
	HashMap<String, Integer> postLabels = new HashMap<String, Integer>();
	HashMap<String, BlogPost> postInstances = new HashMap<String, BlogPost>();
	int TP = 0, FP = 0, TN = 0, FN = 0;

	public void loadPosts(String fileList, String annotator) {
		postLabels.clear();
		postInstances.clear();
		DatabaseAdapter ca = new DatabaseAdapter();
		ca.initialize("jdbc:mysql://goanna.cs.rmit.edu.au:56555/research");
		FileInputStream fstream;
		try {
			fstream = new FileInputStream(fileList);
			BufferedReader in = new BufferedReader(new InputStreamReader(
					fstream));
			String line;
			do {
				line = in.readLine();
				if (line != null) {
					String blogID = line.substring(0, line.length() - 2);
					postLabels.put(blogID, Integer.parseInt(line.substring(line
							.length() - 1, line.length())));
					postInstances.put(blogID, ca.getPost(blogID, annotator));
				}
			} while (line != null);
			fstream.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
	}

	public double voteBySentenceCount(String fileList, String annotator) {
		loadPosts(fileList, annotator);
		int correct = 0, wrong = 0;
		int irrCountCorrect = 0, neuCountCorrect = 0, negCountCorrect = 0, mixCountCorrect = 0, posCountCorrect = 0;
		int irrCountWrong = 0, neuCountWrong = 0, negCountWrong = 0, mixCountWrong = 0, posCountWrong = 0;
		TP = 0;
		FP = 0;
		TN = 0;
		FN = 0;
		for (String blogID : postLabels.keySet()) {
			BlogPost post = postInstances.get(blogID);
			int label = postLabels.get(blogID);
			// Debugging info
			// System.err.println(blogID + " " + positiveCount + ":"
			// + negativeCount);
			int driftingCount = post
					.getNumOfSentencesByLabel(Sentence.IRRELEVANT), neuCount = post
					.getNumOfSentencesByLabel(Sentence.NEUTRAL), negCount = post
					.getNumOfSentencesByLabel(Sentence.NEGATIVE), mixCount = post
					.getNumOfSentencesByLabel(Sentence.MIXED), posCount = post
					.getNumOfSentencesByLabel(Sentence.POSITIVE);
			if ((posCount >= negCount && label == 4)
					|| (posCount < negCount && label == 2)) {
				/*
				 * System.out .println(blogID + " " + driftingCount + ":" +
				 * neuCount + ":" + negCount + ":" + mixCount + ":" + posCount +
				 * " " + String.format(".2f", post
				 * .getDriftingnessBySentence()));
				 */
				if (label == 4) {
					TP++;
				} else {
					TN++;
				}
				correct++;
				irrCountCorrect += driftingCount;
				neuCountCorrect += neuCount;
				negCountCorrect += negCount;
				mixCountCorrect += mixCount;
				posCountCorrect += posCount;

			} else {
				// System.err.println(blogID
				// + " "
				// + driftingCount
				// + ":"
				// + neuCount
				// + ":"
				// + negCount
				// + ":"
				// + mixCount
				// + ":"
				// + posCount
				// + " "
				// + String.format("%.2f", post
				// .getDriftingnessBySentence()));
				if (label == 4) {
					FP++;
				} else {
					FN++;
				}
				wrong++;
				irrCountWrong += driftingCount;
				neuCountWrong += neuCount;
				negCountWrong += negCount;
				mixCountWrong += mixCount;
				posCountWrong += posCount;
			}
		}
		System.out.println("Voting by Count of Sentences:\n"
				+ "==========================================================");
		System.out.println(String.format("%-10s%-10s%-10s%-10s%-10s%-10s", "",
				"Irrelev", "Neutral", "Negative", "Mixed", "Positive"));
		// Global average
		System.out.println(String.format(
				"%-10s%-10.2f%-10.2f%-10.2f%-10.2f%-10.2f", "Global",
				(float) (irrCountCorrect + irrCountWrong) / postLabels.size(),
				(float) (neuCountCorrect + neuCountWrong) / postLabels.size(),
				(float) (negCountCorrect + posCountWrong) / postLabels.size(),
				(float) (mixCountCorrect + mixCountWrong) / postLabels.size(),
				(float) (posCountCorrect + posCountWrong) / postLabels.size()));
		// Correct instance average
		System.out.println(String.format(
				"%-10s%-10.2f%-10.2f%-10.2f%-10.2f%-10.2f", "Correct",
				((float) irrCountCorrect / correct),
				((float) neuCountCorrect / correct),
				((float) negCountCorrect / correct),
				((float) mixCountCorrect / correct),
				((float) posCountCorrect / correct)));

		// Incorrect instance average
		System.out.println(String.format(
				"%-10s%-10.2f%-10.2f%-10.2f%-10.2f%-10.2f", "Incorrect",
				((float) irrCountWrong / wrong),
				((float) neuCountWrong / wrong),
				((float) posCountWrong / wrong),
				((float) mixCountWrong / wrong),
				((float) posCountWrong / wrong)));
		printConfusionMatrix();
		System.out.println(String.format("Accuracy: %.2f%%", (double) 100
				* correct / postLabels.size()));
		System.out
				.println("==========================================================");
		// System.out.println("Debug:" + irrCountWrong + ":" + irrCountCorrect
		// + " " + neuCountWrong + ":" + neuCountCorrect + " "
		// + negCountWrong + ":" + negCountCorrect + " " + mixCountWrong
		// + ":" + mixCountCorrect + " " + posCountWrong + ":"
		// + posCountCorrect + " ");
		return (double) correct / postLabels.size();
	}

	public double voteBySentenceLength(String fileList, String annotator) {
		loadPosts(fileList, annotator);
		int correct = 0, wrong = 0;
		int irrLenCorrect = 0, neuLenCorrect = 0, negLenCorrect = 0, mixLenCorrect = 0, posLenCorrect = 0;
		int irrLenWrong = 0, neuLenWrong = 0, negLenWrong = 0, mixLenWrong = 0, posLenWrong = 0;
		TP = 0;
		FP = 0;
		TN = 0;
		FN = 0;
		for (String blogID : postLabels.keySet()) {
			BlogPost post = postInstances.get(blogID);
			int label = postLabels.get(blogID);
			// Debugging info
			// System.err.println(blogID + " " + positiveCount + ":"
			// + negativeCount);
			int driftingLen = post
					.getLenOfSentencesByLabel(Sentence.IRRELEVANT), neuLen = post
					.getLenOfSentencesByLabel(Sentence.NEUTRAL), negLen = post
					.getLenOfSentencesByLabel(Sentence.NEGATIVE), mixLen = post
					.getLenOfSentencesByLabel(Sentence.MIXED), posLen = post
					.getLenOfSentencesByLabel(Sentence.POSITIVE);
			if ((posLen >= negLen && label == 4)
					|| (posLen < negLen && label == 2)) {
				/*
				 * System.out .println(blogID + " " + driftingCount + ":" +
				 * neuCount + ":" + negCount + ":" + mixCount + ":" + posCount +
				 * " " + String.format(".2f", post
				 * .getDriftingnessBySentence()));
				 */
				if (label == 4) {
					TP++;
				} else {
					TN++;
				}
				correct++;
				irrLenCorrect += driftingLen;
				neuLenCorrect += neuLen;
				negLenCorrect += negLen;
				mixLenCorrect += mixLen;
				posLenCorrect += posLen;

			} else {
				/*
				 * System.err.println(blogID + " " + driftingLen + ":" + neuLen
				 * + ":" + negLen + ":" + mixLen + ":" + posLen + " " +
				 * String.format("%.2f", post .getDriftingnessBySentence()));
				 */
				if (label == 4) {
					FP++;
				} else {
					FN++;
				}
				wrong++;
				irrLenWrong += driftingLen;
				neuLenWrong += neuLen;
				negLenWrong += negLen;
				mixLenWrong += mixLen;
				posLenWrong += posLen;
			}
		}
		System.out.println("Voting by Length of Sentences:\n"
				+ "==========================================================");
		System.out.println(String.format("%-10s%-10s%-10s%-10s%-10s%-10s", "",
				"Irrelev", "Neutral", "Negative", "Mixed", "Positive"));
		// Global average
		System.out.println(String.format(
				"%-10s%-10.2f%-10.2f%-10.2f%-10.2f%-10.2f", "Global",
				(float) (irrLenCorrect + irrLenWrong) / postLabels.size(),
				(float) (neuLenCorrect + neuLenWrong) / postLabels.size(),
				(float) (negLenCorrect + posLenWrong) / postLabels.size(),
				(float) (mixLenCorrect + mixLenWrong) / postLabels.size(),
				(float) (posLenCorrect + posLenWrong) / postLabels.size()));
		// Correct instance average
		System.out.println(String.format(
				"%-10s%-10.2f%-10.2f%-10.2f%-10.2f%-10.2f", "Correct",
				((float) irrLenCorrect / correct),
				((float) neuLenCorrect / correct),
				((float) negLenCorrect / correct),
				((float) mixLenCorrect / correct),
				((float) posLenCorrect / correct)));

		// Incorrect instance average
		System.out.println(String.format(
				"%-10s%-10.2f%-10.2f%-10.2f%-10.2f%-10.2f", "Incorrect",
				((float) irrLenWrong / wrong), ((float) neuLenWrong / wrong),
				((float) posLenWrong / wrong), ((float) mixLenWrong / wrong),
				((float) posLenWrong / wrong)));
		printConfusionMatrix();
		System.out.println(String.format("Accuracy: %.2f%%", (double) 100
				* correct / postLabels.size()));
		System.out
				.println("==========================================================");
		// System.out.println("Debug:" + irrCountWrong + ":" + irrCountCorrect
		// + " " + neuCountWrong + ":" + neuCountCorrect + " "
		// + negCountWrong + ":" + negCountCorrect + " " + mixCountWrong
		// + ":" + mixCountCorrect + " " + posCountWrong + ":"
		// + posCountCorrect + " ");
		return (double) correct / postLabels.size();
	}

	public double voteBySentenceTokens(String fileList, String annotator) {
		loadPosts(fileList, annotator);
		int correct = 0, wrong = 0;
		int irrTokCorrect = 0, neuTokCorrect = 0, negTokCorrect = 0, mixTokCorrect = 0, posTokCorrect = 0;
		int irrTokWrong = 0, neuTokWrong = 0, negTokWrong = 0, mixTokWrong = 0, posTokWrong = 0;
		TP = 0;
		FP = 0;
		TN = 0;
		FN = 0;
		for (String blogID : postLabels.keySet()) {
			BlogPost post = postInstances.get(blogID);
			int label = postLabels.get(blogID);
			// Debugging info
			// System.err.println(blogID + " " + positiveCount + ":"
			// + negativeCount);
			int driftingTok = post
					.getNumOfToksOfSentencesByLabel(Sentence.IRRELEVANT), neuTok = post
					.getNumOfToksOfSentencesByLabel(Sentence.NEUTRAL), negTok = post
					.getNumOfToksOfSentencesByLabel(Sentence.NEGATIVE), mixTok = post
					.getNumOfToksOfSentencesByLabel(Sentence.MIXED), posTok = post
					.getNumOfToksOfSentencesByLabel(Sentence.POSITIVE);
			System.err.println(blogID + "," + negTok + "," + posTok + ","
					+ label);
			if ((posTok >= negTok && label == 4)
					|| (posTok < negTok && label == 2)) {

				if (label == 4) {
					TP++;
				} else {
					TN++;
				}
				correct++;
				irrTokCorrect += driftingTok;
				neuTokCorrect += neuTok;
				negTokCorrect += negTok;
				mixTokCorrect += mixTok;
				posTokCorrect += posTok;

			} else {

				if (label == 4) {
					FP++;
				} else {
					FN++;
				}
				wrong++;
				irrTokWrong += driftingTok;
				neuTokWrong += neuTok;
				negTokWrong += negTok;
				mixTokWrong += mixTok;
				posTokWrong += posTok;
			}
		}
		System.out.println("Voting by Num of Tokens in a sentence:\n"
				+ "==========================================================");
		System.out.println(String.format("%-10s%-10s%-10s%-10s%-10s%-10s", "",
				"Irrelev", "Neutral", "Negative", "Mixed", "Positive"));
		// Global average
		System.out.println(String.format(
				"%-10s%-10.2f%-10.2f%-10.2f%-10.2f%-10.2f", "Global",
				(float) (irrTokCorrect + irrTokWrong) / postLabels.size(),
				(float) (neuTokCorrect + neuTokWrong) / postLabels.size(),
				(float) (negTokCorrect + posTokWrong) / postLabels.size(),
				(float) (mixTokCorrect + mixTokWrong) / postLabels.size(),
				(float) (posTokCorrect + posTokWrong) / postLabels.size()));
		// Correct instance average
		System.out.println(String.format(
				"%-10s%-10.2f%-10.2f%-10.2f%-10.2f%-10.2f", "Correct",
				((float) irrTokCorrect / correct),
				((float) neuTokCorrect / correct),
				((float) negTokCorrect / correct),
				((float) mixTokCorrect / correct),
				((float) posTokCorrect / correct)));

		// Incorrect instance average
		System.out.println(String.format(
				"%-10s%-10.2f%-10.2f%-10.2f%-10.2f%-10.2f", "Incorrect",
				((float) irrTokWrong / wrong), ((float) neuTokWrong / wrong),
				((float) posTokWrong / wrong), ((float) mixTokWrong / wrong),
				((float) posTokWrong / wrong)));
		printConfusionMatrix();
		System.out.println(String.format("Accuracy: %.2f%%", (double) 100
				* correct / postLabels.size()));
		System.out
				.println("==========================================================");
		// System.out.println("Debug:" + irrCountWrong + ":" + irrCountCorrect
		// + " " + neuCountWrong + ":" + neuCountCorrect + " "
		// + negCountWrong + ":" + negCountCorrect + " " + mixCountWrong
		// + ":" + mixCountCorrect + " " + posCountWrong + ":"
		// + posCountCorrect + " ");
		return (double) correct / postLabels.size();
	}

	public void printConfusionMatrix() {
		System.out.println("------------------------------------");
		System.out.println("                       Pos   Neg   ");
		System.out.println(String.format(" Predicted as Pos -->  %-6d%-6d", TP,
				FN));
		System.out.println(String.format(" Predicted as Neg -->  %-6d%-6d", FP,
				TN));
		System.out.println("------------------------------------");
	}
}
